/**
 * @file ai_glass_log.c
 * @brief Logging utility implementation for AI Glass application.
 *
 * This file implements a logging framework with multiple severity levels:
 * - INFO: General information messages
 * - DEBUG: Debugging information
 * - ERROR: Error messages
 *
 * The implementation uses a function pointer to route output to the desired
 * output function (defaulting to printf). It includes timestamp formatting
 * and automatic log level prefixing. The log level can be controlled at compile
 * time via the LOG_LEVEL macro.
 *
 * @author Zhang Meng
 * @date 2025-09-25
 * @version 1.0
 * @copyright Copyright (c) 2025
 */

#include <time.h>
#include <stdio.h>
#include <stdarg.h>
#include "ai_glass_log.h"
#include "ai_glass_common.h"
#include "ai_glass_command.h"

/**
 * @brief Global function pointer for log output.
 *
 * This pointer is used to route log messages to a custom output function.
 * By default, it is initialized to NULL and set to default_log_output
 * during ai_glass_log_init().
 */
static log_output_func_t g_log_output_func = NULL;

// Default output function (printf)
static int default_log_output(const char *format, ...)
{
    va_list args;
    va_start(args, format);
    int result = vprintf(format, args);
    va_end(args);
    return result;
}

/**
 * @brief Initialize the logging system with default output function.
 *
 * This function sets the default output function to printf if no custom
 * function has been set. It should be called before using any logging functions.
 *
 * @return None
 */
void ai_glass_log_init(void)
{
    if (g_log_output_func == NULL) {
        g_log_output_func = default_log_output;
    }
}

/**
 * @brief Set the output function for logging.
 *
 * This function allows customizing where log messages are sent by specifying
 * a function that will handle the formatted output.
 *
 * @param func Pointer to the function that will handle log output.
 *             The function should have the same signature as printf.
 * @return None
 */
void ai_glass_log_set_output(log_output_func_t func)
{
    g_log_output_func = func;
}

/**
 * @brief Get the current timestamp as a formatted string.
 *
 * This function generates a formatted timestamp string in the format
 * [HH:MM:SS.mmm] using the current system time.
 *
 * @param buffer Output buffer for the timestamp
 * @param size Size of the output buffer (should be at least 16 bytes)
 * @return Pointer to the buffer containing the timestamp
 */
static char* get_timestamp(char *buffer, size_t size)
{
    struct timespec ts;
    clock_gettime(CLOCK_REALTIME, &ts);

    // Format: [HH:MM:SS.mmm]
    snprintf(buffer, size, "[%02d:%02d:%02d.%03ld]",
             ts.tv_sec / 3600 % 24,
             ts.tv_sec / 60 % 60,
             ts.tv_sec % 60,
             ts.tv_nsec / 1000000);

    return buffer;
}

/**
 * @brief Internal function to log messages with level prefix.
 *
 * This function is used internally by the logging API to format and output
 * log messages with appropriate timestamp and log level prefixes.
 *
 * @param level Log level (LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_ERROR)
 * @param format Format string (like printf)
 * @param args Variable arguments list
 * @return None
 */
static void log_message(int level, const char *format, va_list args)
{
    // Check if the log level is enabled

    #if LOG_LEVEL == 0
        if (level < LOG_LEVEL_INFO) return; // 只允许 INFO 及以上
    #elif LOG_LEVEL == 1
        if (level < LOG_LEVEL_DEBUG) return; // 只允许 DEBUG 及以上
    #elif LOG_LEVEL == 2
        if (level < LOG_LEVEL_ERROR) return; // 只允许 ERROR 及以上
    #endif



    // Get timestamp
    char timestamp[20];
    get_timestamp(timestamp, sizeof(timestamp));

    // Format the log level prefix
    const char *level_str;
    switch (level) {
        case LOG_LEVEL_INFO:
            level_str = "INFO";
            break;
        case LOG_LEVEL_DEBUG:
            level_str = "DEBUG";
            break;
        case LOG_LEVEL_ERROR:
            level_str = "ERROR";
            break;
        default:
            level_str = "UNKNOWN";
            break;
    }

    // Create the full log message
    char log_buffer[512];
    int len = snprintf(log_buffer, sizeof(log_buffer), "%s [%s] ", timestamp, level_str);

    // Append the actual message
    vsnprintf(log_buffer + len, sizeof(log_buffer) - len, format, args);

    // Output the log message
    if (g_log_output_func) {
        g_log_output_func("%s", log_buffer);
    }
}

/**
 * @brief Log an informational message.
 *
 * This function logs a message with the INFO severity level, including
 * timestamp and level prefix. The message is only output if LOG_LEVEL
 * is set to LOG_LEVEL_INFO or lower.
 *
 * @param format Format string (like printf)
 * @param ... Variable arguments
 * @return None
 */
void ai_glass_log_info(const char *format, ...)
{
    va_list args;
    va_start(args, format);
    log_message(LOG_LEVEL_INFO, format, args);
    va_end(args);
}

/**
 * @brief Log a debug message.
 *
 * This function logs a message with the DEBUG severity level, including
 * timestamp and level prefix. The message is only output if LOG_LEVEL
 * is set to LOG_LEVEL_DEBUG or lower.
 *
 * @param format Format string (like printf)
 * @param ... Variable arguments
 * @return None
 */
void ai_glass_log_debug(const char *format, ...)
{
    va_list args;
    va_start(args, format);
    log_message(LOG_LEVEL_DEBUG, format, args);
    va_end(args);
}

/**
 * @brief Log an error message.
 *
 * This function logs a message with the ERROR severity level, including
 * timestamp and level prefix. The message is only output if LOG_LEVEL
 * is set to LOG_LEVEL_ERROR or lower.
 *
 * @param format Format string (like printf)
 * @param ... Variable arguments
 * @return None
 */
void ai_glass_log_error(const char *format, ...)
{
    va_list args;
    va_start(args, format);
    log_message(LOG_LEVEL_ERROR, format, args);
    va_end(args);
}


/**
 * @brief Get the software version information and send it via IPI.
 *
 * This function retrieves the current software version formatted as V[MAJOR].[MINOR].[PATCH]
 * and sends it to the RTT side via IPI communication.
 * The version numbers are retrieved from the
 * SDK_SW_VERSION_MAJOR, SDK_SW_VERSION_MINOR, and SDK_SW_VERSION_PATCH macros.
 *
 * The function first logs the version information and then sends it using the
 * send_glass_command_string function with a custom command ID (0x42) for version information.
 *
 * @return None
 */
void ai_glass_print_sw_version(void) 
{
	char sw_buffer[8];
    ai_glass_log_info("=============================================\n");
	snprintf(sw_buffer, sizeof(sw_buffer), "V%d.%d.%d", SDK_SW_VERSION_MAJOR, SDK_SW_VERSION_MINOR, SDK_SW_VERSION_PATCH);
    ai_glass_log_info("Software version: %s\n", sw_buffer);
    ai_glass_log_info("=============================================\n");
    
    // Define command ID for version information
    #define CMD_VERSION 0x42
    
    // Send version information via IPI using simplified command interface
    if (send_glass_command_string(CMD_VERSION, sw_buffer) == 0)
    {
        ai_glass_log_info("Version information sent via IPI\n");
    }
    else
    {
        ai_glass_log_error("Failed to send version via IPI\n");
    }
}


